package com.companyname.projecttemplate;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.base.core.context.utils.LoggerWrapper;
import com.gitee.magic.core.exception.ApplicationException;
import com.gitee.magic.framework.head.exception.BusinessAdviceException;
import com.gitee.magic.framework.head.exception.BusinessException;

/**
 * 异常示例代码
 * 
 * @author start
 * 
 *         <pre>
 * 异常处理原则： 
 * 	1、尽量不要try异常统一往外抛,争对RuntimeException的子异常
 * 	2、捕获的异常尽量都用throw new ApplicationException(e)往外抛,争对Exception的子异常
 * 	3、业务异常使用：throw new BusinessException 正常逻辑终止
 * 	4、应用异常使用：throw new ApplicationException 存在问题或bug需要终止
 * 	5、由应用异常引起但又无法做出任何处理属于正常的业务场景使用：throw new BusinessAdviceException 存在问题但是无法做出处理的场景，比如：远程文件不存在、HTTP请求超时、短信余额不足等等
 * 	6、catch方法中如果不是throw往外抛的方式，禁止直接使用：e.printStackTrace() 没有日志、没有监控谁能知道发生了什么事，特殊场景必须注释说明
 * 	7、线程、定时任务入口方法使用try catch(Exception e)全局捕获，使用LoggerWrapper.print(e);来记录异常信息
 * 	8、catch(Exception e)属于一棒子打死,注意捕获场景,处理不当就是程序bug
 *         </pre>
 */
public class SampleCodeException {

	protected final Logger LOGGER = LoggerFactory.getLogger(getClass());

	public void testExce() throws IOException {
	}

	public void throwBusinessException() {
		// 注意：在非异常情况下使用
		// 业务请求非异常原因需要终止可使用该异常直接中止请求，如：订单不存在、用户不存在、权限不足
		throw new BusinessException("业务异常终止程序 推荐");
	}

	public void throwApplicationException() {
		// 注意：在非正常逻辑下使用
		// 在业务执行的过程中发现存在非正常逻辑的情况可直接抛ApplicationException,表明运行到该处肯定是存在重大问题
		throw new ApplicationException("应用异常终止程序 要么逻辑有问题，要么出现异常场景，表明程序存在运行问题或bug");
	}

	public void tryNoHandle() {
		// 重点关注
		// 注意：小心使用容易犯错一定要用必须给出明确理由

		// 场景一 任何时候 任何原因都需要禁用printStackTrace() 写跟没写没区别，不建议理论上也不应该出现
		try {
			testExce();
		} catch (IOException e) {
			e.printStackTrace();
		}

		// 场景二 执行某个方法try了异常，对异常做了如下的日志打印不throw也不做其它处理,有日志但定位困难
		try {
			testExce();
		} catch (IOException e) {
			// 不建议没解决框架格式与监控问题
			LOGGER.error(e.getMessage());
			// 优化：解决了框架格式与监控问题,但是程序是否坚固还是个问号程序是会继续向下执行的，这种写法最好在子线程或定时任务入口方法中，不建议写在普通类方法中
			LoggerWrapper.print(e);
		}

		// 场景三 这是一个HTTP调用或文件读取的方法，出现异常这样处理就是把异常直接吃了，不建议这么实现需要throw出来
		try {
			testExce();
		} catch (IOException e) {

		}

		// 场景四 某个方法是否符合一个Long的数值只需要结果true false，只需要对应的结果，可这么实现
		try {
			Long.parseLong("这是值");
			// return true;
		} catch (NumberFormatException e) {
			// return false;
		}
	}

	public void task() {
		try {
			// 子线程、定时任务如需捕获可以在程序主方法直接把所有代码try catch起来,其余子方法内的调用处理规则不变
		} catch (Exception e) {
			LoggerWrapper.print(e);
		}
	}

	public void throwTryBusinessException() {
		// 重点关注
		// BusinessException比较常用但是不能乱用，该写法会屏蔽异常信息，建议换成BusinessAdviceException
		// 支持这种写法但不建议这么干,特殊情况下需要注释说明原因
		try {
			testExce();
		} catch (IOException e) {
			throw new BusinessException(e);
		}
		try {
			testExce();
		} catch (IOException e) {
			throw new BusinessException("不建议特殊情况说明原因");
		}
	}

	public void throwTryBusinessAdviceException() {
		// 引发异常程序层面无法做出处理的写法
		try {
			testExce();
		} catch (SocketTimeoutException e) {
			// 第三方服务不稳定http请求超时这种不属于bug，监控了也无法做出处理
			// 该写法需要仔细考虑用的不好会影响程序监控
			throw new BusinessAdviceException(e, "如果无法处理异常可参考该写法");
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
		try {
			
		} catch (ApplicationException e) {
			if (e.getCause() != null) {
				if (SocketTimeoutException.class.equals(e.getCause().getClass())) {
					throw new BusinessAdviceException(e, "不处理某个异常");
				}
			}
			throw e;
		} 
	}

	public void throwTryApplicationException() {
		// 极力推荐
		try {
			testExce();
		} catch (IOException e) {
			// 90%以上的异常正确处理方式都应该以这种写法来进行处理，该写法可能会误报异常信息后续做优化
			throw new ApplicationException(e);
		}
		try {
			SimpleDateFormat sdf = new SimpleDateFormat();
			sdf.parse("转换参数");
		} catch (ParseException e) {
//			throw new BusinessAdviceException(e, "这里就不允许这么写,转换参数就应该在入传前做校验");
			throw new ApplicationException(e);
		}
		// 特殊处理某个异常的场景
		try {
			testExce();
		} catch (IOException e) {
			if (e.getCause() != null) {
				if (SocketTimeoutException.class.equals(e.getCause().getClass())) {
					throw new BusinessAdviceException(e, "不处理某个异常");
				}
			}
			throw new ApplicationException(e);
		}
	}

	public void handleMultiple() {
		// 多方案处理模式参考 如果要捕获全建议直接Exception
		try {
			// 方案1
		} catch (Exception e1) {
			try {
				// 方案2
			} catch (Exception e2) {
				// 也可以参考exception6的写法
				throw new ApplicationException(e2);
			}
		}
	}

	public void xxljob(String param) {
		// xxljob 处理方式这里没引包，写法做参考
		// 1、可以不做任何try{}catch处理，出现异常系统会重试该任务
		// 2、如果遇到异常想暂停当前任务可使用如下写法 可直接捕获Exception
		try {
		} catch (Exception e) {
			LoggerWrapper.print(e);
			//return ReturnT.FAIL;
		}
		//return ReturnT.SUCCESS;
	}

}
